home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / MISC / DTMFF110 / PROCINP.C < prev    next >
C/C++ Source or Header  |  1997-08-05  |  31KB  |  1,105 lines

  1. /*
  2.  *  Routine for processing the keyboard input.
  3.  *
  4.  *  Copyright (C) 1995    Philip VanBaren
  5.  */
  6. #include <stdlib.h>
  7. #include <stdio.h>
  8. #include <time.h>
  9. #include <ctype.h>
  10. #include <string.h>
  11. #include <math.h>
  12. #include <bios.h>
  13.  
  14. #include "freq.h"
  15. #include "fft.h"
  16. #include "extern.h"
  17. #include "display.h"
  18.  
  19. int          display_peak = 0; /* Flag for displaying the peak information */
  20. int          help_mode = 0;    /* Flag indicating help mode 0 (off), 1, or 2 */
  21. int          dtmf_mode = 0;    /* Flag indicating DTMF mode */
  22. int          ctcss_mode = 0;    /* Flag indicating CTCSS mode */
  23. int          log_mode = 0;    /* Flag indicating LogFile mode */
  24. int          gen_ctcss = CTCSS_MAX;    /* generated CTCSS frequency number
  25.                      * (init to none) */
  26. double          err_ctcss;
  27. int          bw_mode = 0;    /* Flag indicating a Black/White palette */
  28. int          freeze = 0;    /* Flag indicating a paused display */
  29. float          freq_scalefactor = 1.0;    /* Scalefactor for increasing the
  30.                      * horizonal scale */
  31. float          freq_base = 0.0;    /* Base frequency for the display */
  32. int          bin = 0;        /* Bin number for cursor display */
  33. int          mic_level = 0;    /* Storage for mic input mixer level (0-100) */
  34. int          ext_level = 0;    /* Storage for ext input mixer level (0-100) */
  35. int          int_level = 0;    /* Storage for int input mixer level (0-100) */
  36. int          i;        /* general miscelaneous */
  37. FILE         *log_file;        /* file pointer of the log_file */
  38.  
  39. void
  40. cleanup_vga( void )
  41. {
  42.   /*
  43.    * Clean up VGA registers so Borland libraries work again.
  44.    */
  45.   outportb( 0x3c4, 2 );
  46.   outportb( 0x3c5, 0x0f );    /* Use all bit planes */
  47. }
  48.  
  49. void
  50. setup_vga( void )
  51. {
  52.   /*
  53.    * Set up VGA registers for fast graphics display
  54.    */
  55.   outportb( 0x3ce, 1 );
  56.   outportb( 0x3cf, 0 );        /* Disable set/reset for all planes */
  57.   outportb( 0x3ce, 3 );
  58.   outportb( 0x3cf, 0 );        /* No rotate, just write data */
  59.   outportb( 0x3ce, 4 );
  60.   outportb( 0x3cf, 3 );        /* Read from bit plane 3 */
  61.   outportb( 0x3ce, 5 );
  62.   outportb( 0x3cf, inportb( 0x3cf ) & 0x70 );    /* Read and write direct to
  63.                          * memory */
  64.   outportb( 0x3ce, 8 );
  65.   outportb( 0x3cf, 0xff );    /* Allow modification of all bits */
  66.   outportb( 0x3c4, 2 );
  67.   outportb( 0x3c5, 12 );    /* Use bit planes 2 and 3 */
  68. }
  69.  
  70. void
  71. draw_threshold_level( int color )
  72. {
  73.   int        y;
  74.  
  75.   if ( threshold_level < 0 )
  76.     threshold_level = 0;
  77.   if ( threshold_level > ys )
  78.     threshold_level = ys;
  79.   y = ( WINDOW_BOTTOM - WINDOW_TOP ) * threshold_level / ys;
  80.   y = ( WINDOW_BOTTOM ) - y;
  81.   draw_line( WINDOW_LEFT - 1, y, WINDOW_RIGHT + 1, y, color );
  82. }
  83.  
  84. void
  85. input_text( char *text, int maxlen, int x, int y )
  86. {
  87.   /*
  88.    * Input a line of text using graphical display at (x,y) Maximum length
  89.    * allowed for input is given by maxlen The input begins with the current
  90.    * contents of text, so this must be initialized before calling the
  91.    * routine.
  92.    */
  93.   int        c = 0;
  94.   int        count;
  95.   char        ach[3];
  96.   ach[1] = '_';
  97.   ach[2] = 0;
  98.  
  99.   draw_text_left( x, y, text );
  100.   count = strlen( text );
  101.   x += count * _font_width;
  102.   draw_text_left( x, y, "_" );
  103.  
  104.   while ( ( c != 0x0d ) && ( c != 0x0a ) )
  105.   {
  106.     c = draw_getch(  );
  107.  
  108.     if ( ( ( c == 0x08 ) || ( c == 0x7f ) ) && count )
  109.     {
  110.       count--;
  111.       x -= _font_width;
  112.       draw_bar( x, y - 1, x + 2 * _font_width, y + _font_height, 0 );
  113.       draw_text_left( x, y, "_" );
  114.     }
  115.     else if ( count < ( maxlen - 1 ) )
  116.     {
  117.       if ( ( c >= '0' && c <= '9' ) || ( c >= 'A' && c <= 'Z' ) || ( c >= 'a' && c <= 'z' )
  118.        || c == '.' || c == '\\' || c == '/' || c == ':'
  119.        || c == '*' || c == '#' || c == '-' )
  120.       {
  121.     draw_bar( x, y - 1, x + _font_width, y + _font_height, 0 );
  122.  
  123.     ach[0] = c;
  124.     text[count] = c;
  125.     draw_text_left( x, y, ach );
  126.     count++;
  127.     x += _font_width;
  128.       }
  129.     }
  130.     if ( c == 0x1b )
  131.     {
  132.       count = 0;
  133.       break;
  134.     }
  135.   }
  136.   text[count] = 0;
  137. }
  138.  
  139. void
  140. update_display( void )
  141. {
  142.   /* Update the frequency and amplitude information displayed while */
  143.   /* the input is frozen. */
  144.  
  145.   char        ach[100];
  146.   double    re, im;
  147.   double    amp, db;
  148.  
  149.   int        bri = BitReversed[bin];
  150.   re = fftdata[bri];
  151.   im = fftdata[bri + 1];
  152.  
  153.   amp = sqrt( re * re + im * im ) / 32768.0;
  154.  
  155.   if ( amp != 0 )
  156.     db = 20 * log10( amp );
  157.   else
  158.     db = -100;
  159.  
  160.   draw_bar( 0, 21, 160, 71, 0 );
  161.   sprintf( ach, " Freq: %7.5g Hz ", ( double ) bin * SampleRate / fftlen );
  162.   draw_text_left( 0, 22, ach );
  163.   sprintf( ach, "  Amp: %7.5g   ", amp );
  164.   draw_text_left( 0, 34, ach );
  165.   sprintf( ach, "       %7.5g db ", db );
  166.   draw_text_left( 0, 46, ach );
  167. }
  168.  
  169.  
  170. void
  171. highlight( int on )
  172. {
  173.   /* Turn highlighting of a specified bin on the display on (1) or off (0) */
  174.  
  175.   int        pos;
  176.   double    freq = ( double ) bin * ( double ) SampleRate / fftlen;
  177.   if ( logfreq )
  178.     pos = floor( log( freq / freq_base ) / log( fftlen / 2 ) * freq_scalefactor * ( double ) ( WINDOW_RIGHT - WINDOW_LEFT ) + 0.5 );
  179.   else
  180.     pos = floor( ( freq - freq_base ) * ( double ) ( WINDOW_RIGHT - WINDOW_LEFT ) / ( double ) SampleRate * freq_scalefactor * 2.0 + 0.5 );
  181.  
  182.   if ( on )
  183.   {
  184.     draw_line( WINDOW_LEFT + pos, WINDOW_TOP, WINDOW_LEFT + pos, lasty[pos], DARK_HIGHLIGHT );
  185.     draw_line( WINDOW_LEFT + pos, lasty[pos], WINDOW_LEFT + pos, WINDOW_BOTTOM, LIGHT_HIGHLIGHT );
  186.   }
  187.   else
  188.   {
  189.     draw_line( WINDOW_LEFT + pos, WINDOW_TOP, WINDOW_LEFT + pos, lasty[pos], 0 );
  190.     draw_line( WINDOW_LEFT + pos, lasty[pos], WINDOW_LEFT + pos, WINDOW_BOTTOM, GRAPH_COLOR );
  191.   }
  192. }
  193.  
  194. void
  195. help_freze( void )
  196. {
  197.   draw_bar( WINDOW_LEFT - 5, MGY - 40, WINDOW_RIGHT + 5, MGY + _font_height, 0 );
  198.   draw_text_centered( MGX, MGY - 12, "Use arrows to move, Shift_arrows, Home & End to move quickly" );
  199.   draw_text_centered( MGX, MGY, "Enter to save to disk, Space to continue" );
  200. }
  201.  
  202. int
  203. process_input( int c, int repetitions )
  204. {
  205.   /* Process any keyboard input received by the program */
  206.   char        ach[50];
  207.   int        i;
  208.  
  209.   if ( c == 0 )
  210.     return ( 0 );
  211.  
  212.   if ( freeze )
  213.     highlight( 0 );
  214.  
  215.   if ( c == ' ' )               /* Toggle freeze mode on/off */
  216.   {
  217.     freeze = !freeze;
  218.     if ( freeze )
  219.     {
  220.       if ( help_mode )
  221.       {
  222.     help_mode = 0;
  223.     update_header(    );
  224.       }
  225.       if ( ( double ) bin < freq_base * fftlen / SampleRate )
  226.     bin = ceil( freq_base * fftlen / SampleRate );
  227.       if ( ( double ) bin > maxfreq * fftlen / SampleRate )
  228.     bin = floor( maxfreq * fftlen / SampleRate );
  229.  
  230.       help_freze(  );
  231.  
  232.       update_display(  );
  233.     }
  234.     else
  235.     {
  236.       draw_bar( 0, 21, 160, 71, 0 );
  237.       update_header(  );
  238.     }
  239.   }
  240.   if ( dtmf_mode || ctcss_mode )
  241.   {
  242.     if ( c == PG_UP )
  243.     {
  244.       draw_threshold_level( 0 );
  245.       threshold_level += ys / 50;
  246.       draw_threshold_level( TEXT_COLOR );
  247.     }
  248.     if ( c == PG_DN )
  249.     {
  250.       draw_threshold_level( 0 );
  251.       threshold_level -= ys / 50;
  252.       draw_threshold_level( TEXT_COLOR );
  253.     }
  254.     if ( c == 'G' || c == 'g' )
  255.     {
  256.       log_mode = !log_mode;
  257.       if ( log_mode )
  258.       {
  259.     log_file = fopen( "dtmf_fft.log", "a" );
  260.     if ( log_file == NULL )
  261.       log_mode = 0;
  262.       }
  263.       else
  264.       {
  265.     fclose( log_file );
  266.       }
  267.       update_header(  );
  268.     }
  269.   }
  270.   if ( ( c == 'D' || c == 'd' ) && !ctcss_mode )        /* Toggle DTMF mode */
  271.   {
  272.     dtmf_mode = !dtmf_mode;
  273.     if ( dtmf_mode )
  274.     {
  275.       halt_soundcard(  );
  276.       EndFFT(  );
  277.       SampleRate = 5000L;
  278.       fftlen = 128;
  279.       logfreq = 0;
  280.       freq_scalefactor = 1.0;
  281.       InitializeFFT( fftlen );
  282.       compute_window_function(    );
  283.       /* Flush the buffers */
  284.       for ( i = 0; i < fftlen / 2; i++ )
  285.     displayval[i] = 0;
  286.       for ( i = 0; i < fftlen; i++ )
  287.     fftdata[i] = 0;
  288.       /* Re-initialize the display */
  289.       p_dtmf = 0;
  290.       dtmf_nr[0] = 0;
  291.       setup_xscale(  );
  292.       update_header(  );
  293.       reset_soundcard(    );
  294.     }
  295.     else
  296.     {
  297.       update_header(  );
  298.       draw_threshold_level( 0 );
  299.     }
  300.   }
  301.   else if ( ( c == 'T' || c == 't' ) && !dtmf_mode )    /* Toggle CTCSS mode */
  302.   {
  303.     ctcss_mode = !ctcss_mode;
  304.     if ( ctcss_mode )
  305.     {
  306.       halt_soundcard(  );
  307.       EndFFT(  );
  308.       SampleRate = 5000L;
  309.       fftlen = 2048;
  310.       logfreq = 1;
  311.       freq_scalefactor = 1.0;
  312.       InitializeFFT( fftlen );
  313.       compute_window_function(    );
  314.       /* Flush the buffers */
  315.       for ( i = 0; i < fftlen / 2; i++ )
  316.     displayval[i] = 0;
  317.       for ( i = 0; i < fftlen; i++ )
  318.     fftdata[i] = 0;
  319.       p_dtmf = 0;
  320.       dtmf_nr[0] = 0;
  321.       /* Re-initialize the display */
  322.       setup_xscale(  );
  323.       update_header(  );
  324.       reset_soundcard(    );
  325.     }
  326.     else
  327.     {
  328.       update_header(  );
  329.       draw_threshold_level( 0 );
  330.     }
  331.   }
  332.   else if ( freeze )
  333.   {
  334.     /* Keys only valid in freeze-display */
  335.     if ( ( c == 0x0d ) || ( c == 0x0a ) )    /* <CR> saves the spectrum
  336.                          * data to a file */
  337.     {
  338.       char        filename[30];
  339.       draw_bar( WINDOW_LEFT - 5, MGY - 1, WINDOW_RIGHT + 5, MGY + _font_height, 0 );
  340.       draw_text_left( MGX - 156, MGY, "File in which to save this spectrum:" );
  341.  
  342.       filename[0] = 0;
  343.       input_text( filename, sizeof( filename ), MGX + 140, MGY );
  344.       if ( filename[0] != 0 )
  345.       {
  346.     clock_t          clk;
  347.     FILE         *fp = fopen( filename, "w" );
  348.     if ( fp )
  349.     {
  350.       for ( i = 0; i < fftlen / 2; i++ )
  351.       {
  352.         double      re, im;
  353.         re = fftdata[BitReversed[i]] / 32768.0;
  354.         fprintf( fp, "%g\t%g\n", ( double ) i / ( double ) fftlen
  355.              * ( double ) SampleRate, re );
  356.       }
  357.       fclose( fp );
  358.       sprintf( ach, "Spectrum data saved in %s", filename );
  359.     }
  360.     else
  361.       sprintf( ach, "Unable to open (%s)", filename );
  362.  
  363.     draw_bar( WINDOW_LEFT - 5, MGY - 1, WINDOW_RIGHT + 5, MGY + _font_height, 0 );
  364.     draw_text_centered( MGX, MGY, ach );
  365.  
  366.     clk = clock(  );
  367.     while ( !draw_getkey(  ) && ( ( clock(    ) - clk ) < CLOCKS_PER_SEC * 3 ) );
  368.       }
  369.       draw_bar( WINDOW_LEFT - 5, MGY - 13, WINDOW_RIGHT + 5, MGY + _font_height, 0 );
  370.       help_freze(  );
  371.     }
  372.     if ( c == LEFT_ARROW )    /* Move the cursor one bin left */
  373.       if ( !( bioskey( 2 ) & 3 ) )    /* if no shift key is pressed */
  374.       {
  375.     double          current;
  376.     bin -= repetitions;
  377.     if ( bin <= 0 )
  378.     {
  379.       if ( logfreq )
  380.         bin = 1;
  381.       else
  382.         bin = 0;
  383.     }
  384.     current = ( double ) bin *( double ) SampleRate / ( double ) fftlen;
  385.     if ( current < freq_base )
  386.     {
  387.       freq_base = current;
  388.       /* Re-initialize the display */
  389.       setup_xscale(     );
  390.     }
  391.     update_display(     );
  392.       }
  393.       else
  394.       {                /* Move the cursor 10 bins left */
  395.     double          current;
  396.     bin -= 10 * repetitions;
  397.     if ( bin <= 0 )
  398.     {
  399.       if ( logfreq )
  400.         bin = 1;
  401.       else
  402.         bin = 0;
  403.     }
  404.     current = ( double ) bin *( double ) SampleRate / ( double ) fftlen;
  405.     if ( current < freq_base )
  406.     {
  407.       freq_base = current;
  408.       /* Re-initialize the display */
  409.       setup_xscale(     );
  410.     }
  411.     update_display(     );
  412.       }
  413.     else if ( c == RIGHT_ARROW )/* Move the cursor one bin right */
  414.       if ( !( bioskey( 2 ) & 3 ) )    /* if no shift key is pressed */
  415.       {
  416.     double          current;
  417.     bin += repetitions;
  418.     if ( bin >= fftlen / 2 )
  419.       bin = fftlen / 2 - 1;
  420.     current = ( double ) bin *( double ) SampleRate / ( double ) fftlen;
  421.     if ( current > maxfreq )
  422.     {
  423.       if ( logfreq )
  424.         freq_base = current / exp( log( fftlen / 2 ) / freq_scalefactor );
  425.       else
  426.         freq_base = current - ( double ) SampleRate / ( freq_scalefactor * 2.0 );
  427.       /* Re-initialize the display */
  428.       setup_xscale(     );
  429.     }
  430.     update_display(     );
  431.       }
  432.       else
  433.       {
  434.     double          current;
  435.     bin += 10 * repetitions;
  436.     if ( bin >= fftlen / 2 )
  437.       bin = fftlen / 2 - 1;
  438.     current = ( double ) bin *( double ) SampleRate / ( double ) fftlen;
  439.     if ( current > maxfreq )
  440.     {
  441.       if ( logfreq )
  442.         freq_base = current / exp( log( fftlen / 2 ) / freq_scalefactor );
  443.       else
  444.         freq_base = current - ( double ) SampleRate / ( freq_scalefactor * 2.0 );
  445.       /* Re-initialize the display */
  446.       setup_xscale(     );
  447.     }
  448.     update_display(     );
  449.       }
  450.     else if ( c == HOME )    /* Move the cursor to the lowest frequency */
  451.     {
  452.       if ( logfreq )
  453.     bin = 1;
  454.       else
  455.     bin = 0;
  456.       update_display(  );
  457.       if ( ( logfreq && ( freq_base > ( ( double ) SampleRate / ( double ) fftlen ) ) )
  458.        || ( !logfreq && ( freq_base > 0 ) ) )
  459.       {
  460.     freq_base = 0;
  461.     /* Re-initialize the display */
  462.     setup_xscale(  );
  463.       }
  464.     }
  465.     else if ( c == END )    /* Move the cursor to the highest frequency */
  466.     {
  467.       bin = fftlen / 2 - 1;
  468.       update_display(  );
  469.       if ( maxfreq < ( double ) SampleRate / 2 )
  470.       {
  471.     freq_base = SampleRate / 2;
  472.     /* Re-initialize the display */
  473.     setup_xscale(  );
  474.       }
  475.     }
  476.   }
  477.   else if ( !dtmf_mode && !ctcss_mode )
  478.   {
  479.     /* Keys only valid in non-freeze display */
  480.     if ( c == HOME )        /* Move the cursor to the lowest frequency */
  481.     {
  482.       if ( logfreq && ( freq_base > ( ( double ) SampleRate / ( double ) fftlen ) ) )
  483.       {
  484.     /* Re-initialize the display */
  485.     freq_base = 0;
  486.     setup_xscale(  );
  487.       }
  488.       else if ( !logfreq && ( freq_base > 0 ) )
  489.       {
  490.     /* Re-initialize the display */
  491.     freq_base = 0;
  492.     setup_xscale(  );
  493.       }
  494.     }
  495.     else if ( c == END )    /* Move the cursor to the highest frequency */
  496.     {
  497.       if ( maxfreq < ( double ) SampleRate / 2 )
  498.       {
  499.     freq_base = SampleRate / 2;
  500.     /* Re-initialize the display */
  501.     setup_xscale(  );
  502.       }
  503.     }
  504.     else if ( c == 'H' || c == 'h' || c == '?' || c == '/' )    /* Toggle help mode */
  505.     {
  506.       help_mode++;
  507.       if ( help_mode > 2 )
  508.     help_mode = 0;
  509.  
  510.       if ( help_mode )
  511.     show_help(  );
  512.       else
  513.     update_header(    );
  514.     }
  515.     else if ( c == 'F' || c == 'f' )    /* Change the FFT length */
  516.     {
  517.       halt_soundcard(  );
  518.       EndFFT(  );
  519.       if ( c == 'f' )
  520.       {
  521.     for ( i = 0; i < repetitions; i++ )
  522.     {
  523.       fftlen *= 2;
  524.       if ( fftlen > MAX_LEN )
  525.         fftlen = 8;
  526.     }
  527.       }
  528.       else
  529.       {
  530.     for ( i = 0; i < repetitions; i++ )
  531.     {
  532.       fftlen /= 2;
  533.       if ( fftlen < 8 )
  534.         fftlen = MAX_LEN;
  535.     }
  536.       }
  537.       InitializeFFT( fftlen );
  538.       compute_window_function(    );
  539.       /* Flush the buffers */
  540.       for ( i = 0; i < fftlen / 2; i++ )
  541.     displayval[i] = 0;
  542.       for ( i = 0; i < fftlen; i++ )
  543.     fftdata[i] = 0;
  544.       /* Re-initialize the display */
  545.       setup_xscale(  );
  546.       if ( help_mode )
  547.     show_help(  );
  548.       else
  549.     update_header(    );
  550.       reset_soundcard(    );
  551.     }
  552.     else if ( c == 'R' || c == 'r' )    /* Change the sampling rate */
  553.     {
  554.       char        in[6];
  555.       draw_bar( WINDOW_LEFT - 5, MGY - 1, WINDOW_RIGHT + 5, MGY + _font_height, 0 );
  556.       draw_text_left( MGX - 80, MGY, "Sampling rate: " );
  557.  
  558.       in[0] = 0;
  559.       input_text( in, sizeof( in ), MGX + 40, MGY );
  560.       if ( in[0] != 0 )
  561.       {
  562.     halt_soundcard(     );
  563.  
  564.     SampleRate = atol( in );
  565.     if ( SampleRate < 5000L )
  566.       SampleRate = 5000L;
  567.     if ( SampleRate > 88200L )
  568.       SampleRate = 88200L;
  569.  
  570.     reset_soundcard(  );
  571.  
  572.     /* Re-initialize the display */
  573.     setup_xscale(  );
  574.       }
  575.       if ( help_mode )
  576.     show_help(  );
  577.       else
  578.     update_header(    );
  579.     }
  580.   }
  581.  
  582.   /* Keys valid in both freeze and non-freeze mode */
  583.  
  584.   if ( c == 'I' || c == 'i' )
  585.   {
  586.     char     *p, *s;
  587.     int          valid;
  588.  
  589.     draw_bar( WINDOW_LEFT - 5, MGY - 40, WINDOW_RIGHT + 5, MGY + 8, 0 );
  590.     draw_fontcolor( BORDER_COLOR );
  591.     draw_text_left( WINDOW_LEFT, MGY - 12, "DTMF number to compose: " );
  592.  
  593.     dtmf_nr[0] = 0;
  594.     input_text( dtmf_nr, 64, WINDOW_LEFT, MGY );    /* maximum 64 DTMF
  595.                              * numbers */
  596.     draw_bar( WINDOW_LEFT - 5, MGY - 16, WINDOW_RIGHT + 5, MGY + 8, 0 );
  597.     p = s = dtmf_nr;
  598.     valid = 0;
  599.     while ( *p != 0 )
  600.     {
  601.       if ( *p >= 'a' && *p <= 'd' )
  602.     *p &= ~0x20;        /* upper case */
  603.       if ( !( *p >= '0' && *p <= '9' ) && !( *p >= 'A' && *p <= 'D' )
  604.        && *p != '*' && *p != '#' )
  605.     *p = '-';
  606.       else
  607.     valid = 1;
  608.       if ( valid )
  609.     *s++ = *p;
  610.       p++;
  611.     }
  612.     while ( *--s == '-' )
  613.       ;
  614.     *++s = 0;
  615.     update_header(  );
  616.   }
  617.   else if ( c == 'A' || c == 'a' )
  618.   {
  619.     char      str[10];
  620.     int          m = 0;
  621.     int          err;
  622.     int          old_ctcss;
  623.  
  624.     draw_bar( 0, 0, 639, 92, 0 );
  625.     draw_fontcolor( TEXT_COLOR );
  626.     draw_text_centered( ( WINDOW_LEFT + WINDOW_RIGHT ) / 2, 2,
  627.     "Arrows to move (\033 \032 \030 \031) / Esc to exit / Enter when done" );
  628.     draw_fontcolor( LABEL_COLOR );
  629.     draw_text_left( WINDOW_LEFT, 15, "Choose a tone frequency:" );
  630.     draw_fontcolor( TEXT_COLOR );
  631.     draw_text_left( WINDOW_LEFT + 248, 15, "SPACE toggles" );
  632.     draw_fontcolor( GRAPH_COLOR );
  633.     draw_text_left( WINDOW_LEFT + 366, 15, "active" );
  634.     draw_fontcolor( TEXT_COLOR );
  635.     draw_text_left( WINDOW_LEFT + 426, 15, "/" );
  636.     draw_fontcolor( BORDER_COLOR );
  637.     draw_text_left( WINDOW_LEFT + 440, 15, "inactive" );
  638.     old_ctcss = gen_ctcss;
  639.     do
  640.     {
  641.       switch ( m )
  642.       {
  643.     case ' ':
  644.       if ( gen_ctcss < CTCSS_MAX )
  645.         if ( gen_ctcss < 32 )
  646.           ctcss_act1 ^= 1L << gen_ctcss;
  647.         else
  648.           ctcss_act2 ^= 1L << ( gen_ctcss - 32 );
  649.       break;
  650.     case LEFT_ARROW:
  651.       if ( gen_ctcss >= 1 )
  652.         gen_ctcss--;
  653.       break;
  654.     case RIGHT_ARROW:
  655.       if ( gen_ctcss < CTCSS_MAX )
  656.         gen_ctcss++;
  657.       break;
  658.     case UP_ARROW:
  659.       if ( gen_ctcss >= 10 )
  660.         gen_ctcss -= 10;
  661.       break;
  662.     case DOWN_ARROW:
  663.       if ( gen_ctcss <= CTCSS_MAX - 10 )
  664.         gen_ctcss += 10;
  665.       break;
  666.       }
  667.       for ( i = 0; i <= CTCSS_MAX; i++ )
  668.       {
  669.     if ( i == CTCSS_MAX )
  670.       sprintf( str, "%s", "none" );
  671.     else
  672.       sprintf( str, "%5.1f", f_ctcss[i] );
  673.     if ( i == gen_ctcss )
  674.       if ( i < CTCSS_MAX &&
  675.            ( i < 32 ? ctcss_act1 >> i : ctcss_act2 >> ( i - 32 ) ) & 1 )
  676.         draw_fontcolor( TEXT_COLOR );
  677.       else
  678.         draw_fontcolor( LABEL_COLOR );
  679.     else if ( i < CTCSS_MAX &&
  680.            ( i < 32 ? ctcss_act1 >> i : ctcss_act2 >> ( i - 32 ) ) & 1 )
  681.       draw_fontcolor( GRAPH_COLOR );
  682.     else
  683.       draw_fontcolor( BORDER_COLOR );
  684.     draw_text_left( WINDOW_LEFT + ( i % 10 ) * 52, 29 + 11 * ( i / 10 ), str );
  685.       }
  686.     } while ( ( m = draw_getkey(  ) ) != 0x0d && ( m != 0x1b ) );
  687.  
  688.     if ( m == 0x1b )
  689.       gen_ctcss = old_ctcss;
  690.     else
  691.     {
  692.       halt_soundcard(  );
  693.       err_ctcss = generate_CTCSS( gen_ctcss );
  694.       reset_soundcard(    );
  695.     }
  696.     draw_bar( 0, 0, 639, 92, 0 );
  697.     update_header(  );
  698.   }
  699.   else if ( c == TAB )
  700.   {
  701.     dtmf_mode = ctcss_mode = 0;
  702.     draw_threshold_level( 0 );
  703.     update_header(  );
  704.     if ( dtmf_nr[0] != 0 )
  705.     {
  706.       draw_fontcolor( TEXT_COLOR );
  707.       draw_bar( WINDOW_LEFT - 5, MGY - 16, WINDOW_RIGHT + 5, MGY + _font_height, 0 );
  708.       draw_text_left( WINDOW_LEFT, MGY - 12, "Composing: " );
  709.       halt_soundcard(  );
  710.       generate_DTMF( dtmf_nr );
  711.       reset_soundcard(    );
  712.       update_header(  );
  713.     }
  714.   }
  715.   else if ( c == UP_ARROW )
  716.   {                /* Increase the vertical scale factor */
  717.     if ( dtmf_mode || ctcss_mode )
  718.       draw_threshold_level( 0 );
  719.     {
  720.       double        last_ys = ys;
  721.       for ( i = 0; i < repetitions; i++ )
  722.       {
  723.     if ( ys > 0.15 )
  724.     {
  725.       ys -= 0.1;
  726.     }
  727.     else if ( ys > 0.01 )
  728.     {
  729.       ys -= 0.01;
  730.       if ( ys < 0.01 )
  731.         ys = 0.01;
  732.     }
  733.       }
  734.       if ( ys != last_ys )
  735.     setup_linscales(  );
  736.     }
  737.     if ( dtmf_mode || ctcss_mode )
  738.       draw_threshold_level( TEXT_COLOR );
  739.     amplitude_scale(  );
  740.   }
  741.   else if ( c == DOWN_ARROW )
  742.   {                /* Decrease the vertical scale factor */
  743.     if ( dtmf_mode || ctcss_mode )
  744.       draw_threshold_level( 0 );
  745.     {
  746.       double        last_ys = ys;
  747.       for ( i = 0; i < repetitions; i++ )
  748.       {
  749.     if ( ys < 0.095 )
  750.     {
  751.       ys += 0.01;
  752.     }
  753.     else if ( ys < 2.00 )
  754.     {
  755.       ys += 0.1;
  756.       if ( ys > 2.0 )
  757.         ys = 2.0;
  758.     }
  759.       }
  760.       if ( ys != last_ys )
  761.     setup_linscales(  );
  762.     }
  763.     if ( dtmf_mode || ctcss_mode )
  764.       draw_threshold_level( TEXT_COLOR );
  765.     amplitude_scale(  );
  766.   }
  767.   else if ( ( c == '<' ) || ( c == CTRL_LEFT ) || ( c == ALT_LEFT ) )
  768.   {                /* Decrease the horizontal scale factor */
  769.     if ( freq_scalefactor > 1.0 )
  770.     {
  771.       for ( i = 0; ( freq_scalefactor > 1.0 ) && ( i < repetitions ); i++ )
  772.       {
  773.     freq_scalefactor *= 0.84089641525371;    /* 1/(2^0.25) */
  774.     if ( logfreq )
  775.       freq_base *= exp( log( fftlen / 2 ) * 0.07955179237314 / freq_scalefactor );
  776.     else
  777.       freq_base -= ( double ) SampleRate *0.03977589618657 / freq_scalefactor;
  778.       }
  779.       /* Re-initialize the display */
  780.       if ( freeze )
  781.       {
  782.     double          current = ( double ) bin * ( double ) SampleRate / ( double ) fftlen;
  783.     xrange_check(  );
  784.     if ( current < freq_base )
  785.     {
  786.       freq_base = current;
  787.     }
  788.     if ( current > maxfreq )
  789.     {
  790.       if ( logfreq )
  791.         freq_base = current / exp( log( fftlen / 2 ) / freq_scalefactor );
  792.       else
  793.         freq_base = current - ( double ) SampleRate / 2.0 / freq_scalefactor;
  794.     }
  795.       }
  796.       setup_xscale(  );
  797.     }
  798.   }
  799.   else if ( ( c == '>' ) || ( c == CTRL_RIGHT ) || ( c == ALT_RIGHT ) )
  800.   {                /* Increase the horizontal scale factor */
  801.     if ( freq_scalefactor < 16.0 )
  802.     {
  803.       for ( i = 0; ( freq_scalefactor < 16.0 ) && ( i < repetitions ); i++ )
  804.       {
  805.     if ( logfreq )
  806.       freq_base *= exp( log( fftlen / 2 ) * 0.07955179237314 / freq_scalefactor );
  807.     else
  808.       freq_base += ( double ) SampleRate *0.03977589618657 / freq_scalefactor;
  809.     freq_scalefactor *= 1.18920711500272;    /* 2^0.25 */
  810.       }
  811.  
  812.       /* Re-initialize the display */
  813.       if ( freeze )
  814.       {
  815.     double          current = ( double ) bin * ( double ) SampleRate / ( double ) fftlen;
  816.     xrange_check(  );
  817.     if ( current < freq_base )
  818.     {
  819.       freq_base = current;
  820.     }
  821.     if ( current > maxfreq )
  822.     {
  823.       if ( logfreq )
  824.         freq_base = current / exp( log( fftlen / 2 ) / freq_scalefactor );
  825.       else
  826.         freq_base = current - ( double ) SampleRate / 2.0 / freq_scalefactor;
  827.     }
  828.       }
  829.       setup_xscale(  );
  830.     }
  831.   }
  832.   else if ( ( c == ',' ) || ( c == LEFT_ARROW ) )
  833.   {                /* Shift the horizontal display to the right */
  834.     if ( maxfreq < ( double ) SampleRate / 2 )
  835.     {
  836.       for ( i = 0; ( i < repetitions ) && ( maxfreq < ( double ) SampleRate / 2 ); i++ )
  837.       {
  838.     if ( logfreq )
  839.       freq_base *= exp( log( fftlen / 2 ) / ( 8.0 * freq_scalefactor ) );
  840.     else
  841.       freq_base += ( double ) SampleRate / ( 16.0 * freq_scalefactor );
  842.     xrange_check(  );
  843.       }
  844.       /* Re-initialize the display */
  845.       if ( freeze )
  846.       {
  847.     double          current = ( double ) bin * ( double ) SampleRate / ( double ) fftlen;
  848.     if ( current < freq_base )
  849.     {
  850.       bin = ceil( freq_base / ( double ) SampleRate * ( double ) fftlen );
  851.       update_display(  );
  852.     }
  853.       }
  854.       setup_xscale(  );
  855.     }
  856.   }
  857.   else if ( ( c == '.' ) || ( c == RIGHT_ARROW ) )
  858.   {                /* Shift the horizontal display to the left */
  859.     if ( ( logfreq && ( freq_base > ( ( double ) SampleRate / ( double ) fftlen ) ) )
  860.      || ( !logfreq && ( freq_base > 0 ) ) )
  861.     {
  862.       for ( i = 0; i < repetitions; i++ )
  863.       {
  864.     if ( ( logfreq && ( freq_base > ( ( double ) SampleRate / ( double ) fftlen ) ) )
  865.          || ( !logfreq && ( freq_base > 0 ) ) )
  866.     {
  867.       if ( logfreq )
  868.         freq_base /= exp( log( fftlen / 2 ) / ( 8.0 * freq_scalefactor ) );
  869.       else
  870.         freq_base -= ( double ) SampleRate / ( 16.0 * freq_scalefactor );
  871.     }
  872.     xrange_check(  );
  873.       }
  874.       /* Re-initialize the display */
  875.       if ( freeze )
  876.       {
  877.     double          current = ( double ) bin * ( double ) SampleRate / ( double ) fftlen;
  878.     if ( current > maxfreq )
  879.     {
  880.       bin = floor( maxfreq / ( double ) SampleRate * ( double ) fftlen );
  881.       if ( bin >= fftlen / 2 )
  882.         bin = fftlen / 2 - 1;
  883.       update_display(  );
  884.     }
  885.       }
  886.       setup_xscale(  );
  887.     }
  888.   }
  889.   else if ( c == 'P' || c == 'p' )      /* Toggle peak display mode on/off */
  890.   {
  891.     display_peak = !display_peak;
  892.     if ( display_peak )
  893.     {
  894.       draw_text_left( PKX - 64, PKY, "Peak at         Hz" );
  895.     }
  896.     else
  897.     {
  898.       draw_bar( PKX - 64, PKY - 1, PKX + 79, PKY + _font_height, 0 );
  899.     }
  900.   }
  901.   else if ( c == 'V' || c == 'v' )      /* Redraw the video display */
  902.   {
  903.     draw_bar( 0, 0, 639, 479, 0 );
  904.  
  905.     /* Refresh the video display */
  906.  
  907.     draw_rectangle( WINDOW_LEFT - 2, WINDOW_TOP - 2, WINDOW_RIGHT + 2, WINDOW_BOTTOM + 2, BORDER_COLOR );
  908.     setup_xscale(  );
  909.     amplitude_scale(  );
  910.     if ( help_mode )
  911.       show_help(  );
  912.     else
  913.       update_header(  );
  914.     if ( display_peak )
  915.     {
  916.       draw_text_left( PKX - 64, PKY, "Peak at         Hz" );
  917.     }
  918.     if ( freeze )
  919.     {
  920.       help_freze(  );
  921.       update_display(  );
  922.     }
  923.     /* Reset the last-value contents */
  924.     for ( i = 0; i < WINDOW_RIGHT - WINDOW_LEFT; i++ )
  925.       lasty[i] = WINDOW_BOTTOM;
  926.   }
  927.   else if ( c == 'S' || c == 's' )      /* Save the current state to an INI
  928.                      * file */
  929.   {
  930.     draw_bar( WINDOW_LEFT, MGY - 1, WINDOW_RIGHT + 5, MGY + _font_height, 0 );
  931.     draw_text_left( MGX - 130, MGY, "Save the current state to: " );
  932.     strncpy( ach, ini_file, 20 );
  933.     input_text( ach, 20, MGX + 86, MGY );
  934.     if ( ach[0] != 0 )
  935.     {
  936.       FILE       *fp;
  937.       strcpy( ini_file, ach );
  938.       fp = fopen( ini_file, "w" );
  939.       if ( fp )
  940.       {
  941.     fprintf( fp, "Soundcard: %d\n", Soundcard );
  942.     fprintf( fp, "Sample rate: %ld\n", SampleRate );
  943.     fprintf( fp, "FFT length: %d\n", fftlen );
  944.     fprintf( fp, "Log freq scale: %d\n", logfreq );
  945.     fprintf( fp, "Max amp: %g\n", ys );
  946.     fprintf( fp, "Base frequency: %g\n", freq_base );
  947.     fprintf( fp, "Frequency factor: %g\n", freq_scalefactor );
  948.     fprintf( fp, "DTMF & CTCSS threshold level: %g\n", threshold_level );
  949.     fprintf( fp, "DTMF delay (100 - 1000 ms): %d\n", 3 * dtmf_delay );
  950.     fprintf( fp, "CTCSS active: 0x%08lX, 0x%08lX\n", ctcss_act1, ctcss_act2 );
  951.     fprintf( fp, "Background color: %d,%d,%d\n", background.red, background.green, background.blue );
  952.     fprintf( fp, "Clipping warning color: %d,%d,%d\n", warn.red, warn.green, warn.blue );
  953.     fprintf( fp, "Graph color: %d,%d,%d\n", graph.red, graph.green, graph.blue );
  954.     fprintf( fp, "Tick mark color: %d,%d,%d\n", tick.red, tick.green, tick.blue );
  955.     fprintf( fp, "Axis label color: %d,%d,%d\n", label.red, label.green, label.blue );
  956.     fprintf( fp, "Border color: %d,%d,%d\n", border.red, border.green, border.blue );
  957.     fprintf( fp, "Text color: %d,%d,%d\n", text.red, text.green, text.blue );
  958.     fprintf( fp, "Cursor upper color: %d,%d,%d\n", darkhl.red, darkhl.green, darkhl.blue );
  959.     fprintf( fp, "Cursor lower color: %d,%d,%d\n", lighthl.red, lighthl.green, lighthl.blue );
  960.     fclose( fp );
  961.       }
  962.       else
  963.       {
  964.     clock_t          clk = clock(  );
  965.     sprintf( ach, "Unable to open %s", ini_file );
  966.     draw_bar( WINDOW_LEFT - 5, MGY - 1, WINDOW_RIGHT + 5, MGY + _font_height, 0 );
  967.     draw_text_centered( MGX, MGY, ach );
  968.     while ( !draw_getkey(  ) && ( ( clock(    ) - clk ) < 3 * CLOCKS_PER_SEC ) );
  969.       }
  970.     }
  971.     if ( help_mode )
  972.       show_help(  );
  973.     else
  974.       update_header(  );
  975.     if ( freeze )
  976.     {
  977.       help_freze(  );
  978.       update_display(  );
  979.     }
  980.   }
  981.   else if ( c == 'C' || c == 'c' )      /* Toggle Black/White palette on/off */
  982.   {
  983.     bw_mode = !bw_mode;
  984.     if ( bw_mode )
  985.       setbwpalette(  );
  986.     else
  987.       setnormalpalette(     );
  988.   }
  989.   else if ( c == 'L' || c == 'l' )      /* Toggle linear/logarithmic
  990.                      * frequency axis */
  991.   {
  992.     /*
  993.      * Toggle between linear and logarithmic and equalizer frequency scale
  994.      */
  995.     logfreq = !logfreq;
  996.  
  997.     if ( freeze )
  998.     {
  999.       double        current;
  1000.       if ( logfreq && ( bin == 0 ) )
  1001.     bin = 1;
  1002.       current = ( double ) bin *( double ) SampleRate / ( double ) fftlen;
  1003.       xrange_check(  );
  1004.       if ( current < freq_base )
  1005.       {
  1006.     freq_base = current;
  1007.       }
  1008.       if ( current > maxfreq )
  1009.       {
  1010.     if ( !logfreq )
  1011.       freq_base = current - ( double ) SampleRate / 2.0 / freq_scalefactor;
  1012.     else
  1013.       freq_base = current / exp( log( fftlen / 2 ) / freq_scalefactor );
  1014.       }
  1015.     }
  1016.     setup_xscale(  );
  1017.   }
  1018.   else if ( mixers )
  1019.   {
  1020.     if ( c == '[' )             /* External jack down */
  1021.     {
  1022.       ext_level -= 2 * repetitions;
  1023.       if ( ext_level < 0 )
  1024.     ext_level = 0;
  1025.       if ( !help_mode )
  1026.       {
  1027.     sprintf( ach, "%3d", ext_level );
  1028.     draw_bar( LVX + 104, LVY - 1, LVX + 127, LVY + _font_height, 0 );
  1029.     draw_text_left( LVX + 104, LVY, ach );
  1030.       }
  1031.       set_mixer( MIXER_EXT, ext_level );
  1032.     }
  1033.     else if ( c == ']' )        /* External jack up */
  1034.     {
  1035.       ext_level += 2 * repetitions;
  1036.       if ( ext_level > 100 )
  1037.     ext_level = 100;
  1038.       if ( !help_mode )
  1039.       {
  1040.     sprintf( ach, "%3d", ext_level );
  1041.     draw_bar( LVX + 104, LVY - 1, LVX + 127, LVY + _font_height, 0 );
  1042.     draw_text_left( LVX + 104, LVY, ach );
  1043.       }
  1044.       set_mixer( MIXER_EXT, ext_level );
  1045.     }
  1046.     else if ( c == '{' )        /* CD input down */
  1047.     {
  1048.       int_level -= 2 * repetitions;
  1049.       if ( int_level < 0 )
  1050.     int_level = 0;
  1051.       if ( !help_mode )
  1052.       {
  1053.     sprintf( ach, "%3d", int_level );
  1054.     draw_bar( LVX + 168, LVY - 1, LVX + 191, LVY + _font_height, 0 );
  1055.     draw_text_left( LVX + 168, LVY, ach );
  1056.       }
  1057.       set_mixer( MIXER_INT, int_level );
  1058.     }
  1059.     else if ( c == '}' )        /* CD input up */
  1060.     {
  1061.       int_level += 2 * repetitions;
  1062.       if ( int_level > 100 )
  1063.     int_level = 100;
  1064.       if ( !help_mode )
  1065.       {
  1066.     sprintf( ach, "%3d", int_level );
  1067.     draw_bar( LVX + 168, LVY - 1, LVX + 191, LVY + _font_height, 0 );
  1068.     draw_text_left( LVX + 168, LVY, ach );
  1069.       }
  1070.       set_mixer( MIXER_INT, int_level );
  1071.     }
  1072.     else if ( c == '(' )        /* Mic input down */
  1073.     {
  1074.       mic_level -= 2 * repetitions;
  1075.       if ( mic_level < 0 )
  1076.     mic_level = 0;
  1077.       if ( !help_mode )
  1078.       {
  1079.     sprintf( ach, "%3d", mic_level );
  1080.     draw_bar( LVX + 32, LVY - 1, LVX + 55, LVY + _font_height, 0 );
  1081.     draw_text_left( LVX + 32, LVY, ach );
  1082.       }
  1083.       set_mixer( MIXER_MIC, mic_level );
  1084.     }
  1085.     else if ( c == ')' )        /* Mic input up */
  1086.     {
  1087.       mic_level += 2 * repetitions;
  1088.       if ( mic_level > 100 )
  1089.     mic_level = 100;
  1090.       if ( !help_mode )
  1091.       {
  1092.     sprintf( ach, "%3d", mic_level );
  1093.     draw_bar( LVX + 32, LVY - 1, LVX + 55, LVY + _font_height, 0 );
  1094.     draw_text_left( LVX + 32, LVY, ach );
  1095.       }
  1096.       set_mixer( MIXER_MIC, mic_level );
  1097.     }
  1098.   }
  1099.  
  1100.   if ( freeze )
  1101.     highlight( 1 );
  1102.  
  1103.   return ( c == 'E' || c == 'e' || c == 'Q' || c == 'q' || c == 0x1b );
  1104. }
  1105.